package sxe.core.cs511.team2_2;

import snobject.*;
import step.EvaluationFailure;
import step.FunctionWrapper;
import step.exceptions.ResourceUnavailableException;
import sxe.core.hash.SQLClientInstance;
import java.text.SimpleDateFormat;

import java.sql.SQLException;
import java.util.*;

/** OVERVIEW:  A class that defines the opcode storetable.  This opcode will take as an argument a data Object to 
 *  store and will store this object in memory.  At a fixed 1 minute granularity, this method will store all data records in memory
 *  to a SQL database using the current time as a key and will clear the memory region. 
 *  The abstraction function is AF(c) = {a structure containing data Objects in memory}.  
 *  The representation invariant is that the structure can not contain null values.
 * @author lisap
 *
 */

public class storetable extends FunctionWrapper {
	
	private snStruct struct = new snStruct();
	private long nexttime = 0;
	private int count = 0;

	/** EFFECTS:  This method takes a data Object as an argument and puts it into a memory region.
	 *  At a fixed 1 minute granularity, this method dumps all data records into a SQL database and clears the shared memory region.
	 * This method is called when this opcode is called in a STEP program.
	 * @param arg a data object to be stored
	 * @return true if the data object was sucessfully stored, false if it was not
	 * @throws EvaluationFailure
	 */
	public snObject Call(snObjectArgList arg) throws EvaluationFailure, ResourceUnavailableException{
		
		struct.put(new snString("" + count), arg.popObject());
		count++;
		Calendar cal = Calendar.getInstance();
		long time = cal.getTimeInMillis();
		if (nexttime == 0) // if this is the first time this function is called, set nexttime appropriately
			nexttime = (long)(time /1000) * 1000 + 1000;
		if (struct.size() > 0 && (time >= nexttime)){
			System.out.println("Caching.  current time " + time + " nexttime " + nexttime);
			storeMemory();
			clearMemory();
			nexttime = nexttime + 1000;
		}
		System.out.println("current time " + time + " nexttime " + nexttime);
		return null;
	}
	
	/** EFFECTS:  Clears the memory region
	 *  MODIFIES:  The memory region of this class
	 * 
	 */
	private void clearMemory(){
		struct.clear();
		count = 0;
	}
	
	/** EFFECTS:  Stores the values currently in the memory region in the SQL database using a String representation of the current time as the key.
	 *  If there is no data in the memory region, this method does nothing.
	 * 
	 */
	private void storeMemory() throws ResourceUnavailableException{
		
		try{
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
			Date nextdate = new Date(nexttime);
			String key = sdf.format(nextdate);
			System.out.println("storing element with key " + key);
			
			SQLClientInstance.getInstance().Put(struct, key);
		}
		catch(SQLException sqe){
			sqe.printStackTrace();
			throw new ResourceUnavailableException("SQLException in put: " + sqe.getMessage());
		}
	}

	
}
